/*
Generic Doubly Linked List and Persistent Settings project
Author: Mark Newcomb Jr.

*/
#ifndef PERSISTENT_SETTINGS_H
#define PERSISTENT_SETTINGS_H

#include <string>
#include <algorithm>
#include <sstream>
#include "FileStorage.h"
#include "DLList.h"

#define NAME_MAXLENGTH 128

#if (MSC_VER > 1000)
#pragma once
#endif

 //everything is inline because it's a template :-(


class PersistentSettings
{
public:
	
	PersistentSettings(std::string fname)
	{
		//load the settings into the list
		Filename = fname;
		//DDList Settings is modified by this
		//VERBOSE
		std::cout<<"PERSISTENTSETTINGS->PersistentSettings()"
		<<"\n\tCreating a new FileStorage object.\n";
		//V
		Storage = new FileStorage(&Settings,Filename);
	}
	~PersistentSettings(){}
	
	//returns every value as a string, which we can then use FromString to 
	//get whatever datatype we want
	std::string Get(std::string name)
	{
		Node<std::string> setting;
		name = this->ToLowerCase(name);
		setting = Settings.pop_name_front(name.c_str());
	
		std::string retString = setting.data;
	
		return retString;
	}
	
	//converts a string s and stores it into t
	//t will be changed by the function
	template<class S>
	bool FromString(S* t, const std::string &s)
	{
	std::istringstream iss(s);
	return !(iss>>*t).fail();
	}
	
	//convert datatype t to a string s
	template<class S>
	bool ToString(std::string &s, S &t)
	{
		std::ostringstream oss;
		oss<<t;
		s = oss.str();
		
		if(!(s.empty())){
			return true;
		}else{
			return false;
			}
	}
	
	
	
	bool Save()
	{
		Storage->Copy_List_From(&Settings);
		bool retValue = Storage->Save("settings.ini");
		return retValue;
	}
	
	bool Save(std::string fname)
	{
		
	
		Storage->Copy_List_From(&Settings);
		return(Storage->Save(fname));
	}


	//sets a value.  if we can't convert inVal's datatype to a string, return false
	//TODO:specialize this template so it doesn't call ToString if inVal is already
	//a std::string
	template<class S>
	bool Set(std::string name, S inVal)
	{
		//change the input value to a string that we can easily store
		std::string settingVal;
		bool convSuccess = this->ToString<S>(settingVal,inVal);
		if(convSuccess == false){
			//VERBOSE
			std::cout<<"Had some trouble converting inVal to a string.\n";
			}
		//convert the name to lower case
		name = this->ToLowerCase(name);
		char *c_name = new char[NAME_MAXLENGTH];
		strcpy(c_name,name.c_str());
		
		
		//VERBOSE
		std::cout<<"\nPERSISTENTSETTINGS->Set().\nName changed to lower case: "<<name<<"\n";
		
		
		Settings.push_front(c_name,settingVal);
		
		std::cout<<"Name being pushed: "<<c_name
		<<" Data being pushed: "<<settingVal<<"\n";
		
	
		
	
		return convSuccess;
	}	


private:
	
	FileStorage* Storage;
	
	std::string Filename;
	
	//use this to convert setting names to lower case
	std::string ToLowerCase(std::string s)
	{
		std::transform(s.begin(),s.end(),s.begin(),::tolower);
	
		return s;
	}
	
	
	//the linked list that will store all of the settings
	DLList<std::string> Settings;
	
	//file storage system
	
};



#endif //PERSISTENT_SETTINGS_H